<!DOCTYPE HTML>
<html>
<head>
<title>函数对象 | AutoHotkey</title>
<meta name="description" content="Function objects are either references to Func objects representing actual functions, or objects which can be called like functions." />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<link href="../static/theme.css" rel="stylesheet" type="text/css" />
<script src="../static/content.js" type="text/javascript"></script>
<script type="text/javascript">$(function(){0<=window.navigator.userAgent.toLowerCase().indexOf("ucbrowser")&&CaoNiMaDeUc()})</script>
</head>
<body>

<h1>函数对象</h1>

<p>"函数对象" 泛指以下内容:</p>
<ul>
  <li>对 <a href="Func.htm">Func 对象</a>的引用, 它表示一个实际的<a href="../Functions.htm">函数</a>; 包含内置函数及脚本定义的函数.</li>
  <li>用户定义的对象, 可以像函数一样调用. 亦称为 "函数子".</li>
  <li>任何其他可以像函数一样调用的对象, 如<a href="#BoundFunc">绑定函数对象</a>或 COM 方法返回的 JavaScript 函数对象.</li>
</ul>
<p>函数对象可用于以下情况:</p>
<ul>
  <li><a href="../commands/Gui.htm#label">GUI 控件事件</a>(G-标签)</li>
  <li><a href="../commands/Hotkey.htm#Functor">热键</a></li>
  <li><a href="../commands/Menu.htm#Functor">菜单</a></li>
  <li><a href="../commands/OnClipboardChange.htm#function">OnClipboardChange()</a></li>
  <li><a href="../commands/OnExit.htm#function">OnExit()</a></li>
  <li><a href="../commands/OnMessage.htm">OnMessage()</a></li>
  <li><a href="../commands/SetTimer.htm#Functor">SetTimer</a></li>
</ul>

<h2 id="User-Defined">用户定义的函数对象</h2>
<!-- TODO: Explain how a user-defined object could be useful -->
<p>用户定义函数对象应遵循以下一般模式:</p>
<pre>class YourClassName {
    Call(a, b) {  <em>; 根据需要声明参数, 或<a href="../Functions.htm#Variadic">数组*</a>.</em>
        <em>;...</em>
    }
    __Call(method, args*) {
        if (method = "")  <em>; 对 <a href="../Functions.htm#DynCall">%fn%()</a> 或 fn.()</em>
            return this.Call(args*)
        if (IsObject(method))  <em>; 如果此函数对象作为方法被使用.</em>
            return this.Call(method, args*)
    }
    <em>;...</em>
}
</pre>
<p>模式中各个部分适用于不同的使用情形, 如下:</p>
<ul>
  <li>如果脚本按 <a href="../Functions.htm#DynCall">%this%()</a> 或 <code>this.()</code> 的形式调用, 则, <code>method</code>(方法名) 的值是空字符串.</li>
  <li>如果对象作为方法被调用, 则 <code>IsObject(method)</code> 返回真, 并且 <code>method</code> 包含关于目标对象的引用. 如: 若 <code>x.y</code> 指向 <code>this</code> 函数对象, 则 <code>x.y()</code> → <code>this[x]()</code> → <code>this.__Call(x)</code> → <code>this.Call(x)</code>.</li>
  <li><span class="ver">[v1.1.20+]:</span> 如果对象被某需要回调函数的内置函数所使用, 如 OnMessage() 或 SetTimer, 则此对象仅需支持 Call 方法即可.</li>
</ul>
<p>上述过程可以直接在 __Call 中完成, 推荐使用 __Call 代替 Call 以便更好的迁移到 <a href="https://www.autohotkey.com/v2/">AutoHotkey v2</a> 版本, 其会改变 <code>%this%()</code> 的行为及调用 CALL 的方法调用.</p>
<h3 id="User-Defined-Examples">示例</h3>
<p>如果要定义多个函数对象类型, 则应将样板代码委托给基类(但如果您要将代码与其他人的组合使用, 请小心冲突). 例如:</p>
<pre id="class_FunctionObject">class FunctionObject {
    __Call(method, args*) {
        if (method = "")
            return this.Call(args*)
        if (IsObject(method))
            return this.Call(method, args*)
    }
}</pre>
<p>下面的例子定义了一个可以调用的函数数组; 调用时, 它依次调用数组的每个元素.</p>
<pre><em>; 此示例需要上面的 <a href="#class_FunctionObject">FunctionObject class</a> 才能工作.</em>
class FuncArrayType extends FunctionObject {
    Call(obj, params*) {
        <em>; 调用函数列表.</em>
        Loop % this.Length()
            this[A_Index].Call(params*)
    }
}

<em>; 创建一个函数数组.</em>
funcArray := new FuncArrayType
<em>; 向数组中添加函数(可以在任何位置完成).</em>
funcArray.Push(Func("One"))
funcArray.Push(Func("Two"))
<em>; 创建一个使用数组作为方法的对象.</em>
obj := {method: funcArray}
<em>; 调用方法.</em>
obj.method("foo", "bar")

One(param1, param2) {
    ListVars
    MsgBox
}
Two(param1, param2) {
    ListVars
    MsgBox
}</pre>

<h2 id="BoundFunc">绑定函数对象<span class="ver">[v1.1.20+]</span></h2>
<p>行为像函数, 但只是将预定义的参数传递给另一个函数.</p>
<p>有两种建立绑定函数对象的方式:</p>
<ul>
  <li>调用 <a href="Func.htm#Bind">Func.Bind()</a> 方法, 其绑定参数值至一个函数.</li>
  <li>调用 <a href="../commands/ObjBindMethod.htm">ObjBindMethod()</a> 函数, 其绑定参数值和方法名至目标对象.</li>
</ul>
<p>调用绑定函数对象, 如下例所示. 不支持其他方法. 当绑定函数对象被调用时, 它调用绑定的函数或方法, 传递绑定的参数和后面跟着的调用者传递的任何参数. 例如:</p>
<pre>fn := Func("RealFn").Bind(1)

%fn%(2)    <em>; 显示 "1, 2"</em>
fn.Call(3) <em>; 显示 "1, 3"</em>

RealFn(a, b) {
    MsgBox %a%, %b%
}</pre>
<p><a href="../commands/ObjBindMethod.htm">ObjBindMethod()</a> 用于绑定无法引用的方法. 例如:</p>
<pre>file := FileOpen(A_ScriptFullPath, "r")
getLine := ObjBindMethod(file, "ReadLine")
MsgBox % %getLine%()  <em>; 显示此文件的第一行.</em></pre>
<p>更多复杂的例子, 请参阅 <a href="../commands/SetTimer.htm#ExampleClass">SetTimer</a>.</p>

</body>
</html>